use crate::boot::db;
use crate::boot::err::MyError;
use crate::lib::{sys_db, util_string};
use crate::model::SysOrgan;
use crate::api::*;
use crate::model::SysRole;

use actix_session::Session;
use actix_files::NamedFile;
use actix_web::{web, Error, HttpResponse, Result, Responder}; 
use rbs::Value as rbv;
use serde_json::{Value};
use std::time;  
use std::collections::HashSet;

// 默认首页
pub async fn index() -> Result<impl Responder> {
    Ok(NamedFile::open("static/html/admin/login.html")?)
} 

pub async fn hello1(session: Session) -> Result<HttpResponse, Error> {
    // 一直访问 hello1 的情况下没问题，如果中断几分钟后再访问，就卡在 db::RB.fetch 这。
    if let Ok(data) = db::RB
        .fetch("select id from sys_organ where id = 4", vec![])
        .await
    {
        log::debug!("11111111:{}", data);
    } else {
        log::error!("{} ", "数据库连接失败！");
    }

    //let s = db::HashData.get("name").unwrap();

    if let Some(v) = db::HashData.get("name") {
        log::info!("从 hashData 中读取数据:{}", v.value());
    }

    if let Some(member_bean) = session.get::<MemberBean>("SessionMemberBean")? { 
      log::info!("session 中有个数据：{:?}", member_bean); 
  } else {
      log::info!("session 中没有数据 。"); 
  };

    Ok(HttpResponse::Ok().body("数据读取成功"))
}

pub async fn hello2() -> Result<HttpResponse, Error> {
    sys_db::test_db().await;

    Ok(HttpResponse::Ok().json(vec!["asdf", "2323", "2323fa"]))
}

pub async fn hello3(session: Session) -> Result<HttpResponse, MyError > {
   let f = NamedFile::open("AAstatic/html/admin/login.html").map_err(|e|  MyError::Io(e) )?;

   let list = db::RB.fetch("select * from aaa", vec![]).await.map_err(|e| MyError::Db(e))?;

   //session.insert("SessionMemberBean", &member_bean).map_err(|e| MyError::Other(e.into()))?;

   //let f = NamedFile::open("AAstatic/html/admin/login.html")?;
   Ok(HttpResponse::Ok().json(""))
}

// 用户登录
pub async fn login(session: Session, data: web::Json<Value>) -> Result<HttpResponse, MyError> {
    let phone = data["phone"].as_str().unwrap_or("");  // 获取参数，转换失败则赋予 ""
    let password = data["password"].as_str().unwrap_or(""); 
    let pas_md5 = util_string::app_md5(password);  // MD5加密

    log::debug!("手机号：{} 密码：{} 加密后密码：{}", phone, password, pas_md5);  
    
    // 执行 sql 语句，并把结果存入 Vec 中，如读取失败则返回错误 MyError::Db 
    let sql = "select * from sys_organ where status > 0 and org_type = 3 and phone = ? and password = ? ";
    let list = db::RB.fetch_decode::<Vec<SysOrgan>>(sql, 
      vec![rbv::String(phone.into()), rbv::String(pas_md5.into())]).await.map_err(|e| MyError::Db(e))?;
     
    // 读取第一条数据，如果不存在则表示数据是空的
    if let Some(record) = list.get(0) {  
        let data = record.to_owned();   // 生成具有所有权的类型实例
        
        let id = data.id.unwrap_or(0);
        let name = data.name.unwrap_or("".into()); 

        if id > 0 {
            // 读取用户权限列表
            let role_sql = format!("select * from sys_role where status > 0 and id in ({}) ;", data.roles.unwrap_or("None".into()));
            let role_list = db::RB.fetch_decode::<Vec<SysRole>>(&role_sql, vec![]).await.map_err(|e|MyError::Db(e))?;
            let mut hash_set = HashSet::<i32>::new();
            for role in role_list {
                let power_list = role.power_list.unwrap_or("".into()); 

                let v = power_list.split(',').map(|v| v.parse::<i32>().unwrap_or(0));

                v.for_each(|power|{
                    _ = &hash_set.insert(power);
                }); 
            }  

            let member_bean = MemberBean{
                id : id,
                name : name,
                powers : hash_set.into_iter().collect::<Vec<i32>>(),
            }; 

            log::info!("member_bean : {:?}", &member_bean);

            if let Ok(_) = session.insert("SessionMemberBean", &member_bean) {
                resp_ok(1, "登录成功",  &member_bean)
            } else {
                resp_err(-1, "保存登录信息失败！") 
            }
        } else {
            resp_err(-1, "账号或密码错误！ " )
        } 
    } else {
        resp_err(-1, "账号或密码错误！ ")
    }  
}

// 测试
pub async fn test(data: web::Json<Value>) -> Result<HttpResponse, Error> {
    let phone = data["phone"].as_str().unwrap_or_else(|| "");
    let password = data["password"].as_str().unwrap_or_else(|| "");
    let pas_md5 = util_string::app_md5(password);

    log::debug!("手机号：{} 密码：{} ", phone, password);



    if let Ok(v) = db::RB
        .fetch("select id,pid,tid,name,roles,roles_scope,roles_office_list,contacts,phone,weixin_open_id from sys_organ where status > 0 and type = 3 and phone = ? and password = ? limit 1", 
               vec![rbv::String(phone.into()), rbv::String(pas_md5.into())])
        .await
    {
        log::info!("{:?}", v); 

        if let Some(array) = v.as_array() {
            if array.len() > 0 {
                // 遍历，获取所有数据
                for item in array {
                    let name = item["name"].as_str().unwrap_or_else(|| "");
                    log::info!("读取数据成功，用户名： {} ", name);
                }

                // 只获取第一条数据
                if let Some(item) = array.get(0) {
                    let name = item["name"].as_str().unwrap_or_else(|| "");
                    log::info!("读取数据成功，用户名： {} ", name);
                }
            } else {
                log::info!("读取到的内容是空的: {}", v); 
            } 
        } else { 
            log::info!("读取到的内容不是数组?: {}", v);
        } 
    } else {
        log::error!("{} ", "数据库连接失败！");
    }

    tokio::task::spawn(async {
        log::info!("xxxxxxxxxxxxxxxxx读取数据库2");
        if let Ok(v) = db::RB
            .fetch("select id from sys_organ where id = 4", vec![])
            .await
        {
            // 休眠请使用该句
            tokio::time::sleep(time::Duration::from_millis(3000)).await;
            // 这里休眠千万不能使用下面这句，这句会堵塞整个tokio进程
            //thread::sleep(time::Duration::from_millis(3000));

            log::debug!("33333333333读取数据库成功:{}", v);
        } else {
            log::error!("{} ", "数据库连接失败！");
        }
    });

    //thread::sleep(time::Duration::from_millis(1000));

    db::HashData.insert("name".to_string(), "laobu".to_string());

    Ok(HttpResponse::Ok().json(vec!["asdf", "2323", "2323fa"]))
}
